// (c) Copyright Cory Plotts.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

namespace Snoop.Infrastructure;

using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

public static class PertinentPropertyFilter
{
    public static bool Filter(object target, PropertyDescriptor property)
    {
        if (target is not DependencyObject dependencyObject)
        {
            return true;
        }

        var attachedPropertyForChildren = (AttachedPropertyBrowsableForChildrenAttribute?)property.Attributes[typeof(AttachedPropertyBrowsableForChildrenAttribute)];

        if (attachedPropertyForChildren is not null)
        {
            var dpd = DependencyPropertyDescriptor.FromProperty(property);
            if (dpd is null)
            {
                return false;
            }

            // Check logical tree
            {
                var currentElement = dependencyObject;
                do
                {
                    currentElement = LogicalTreeHelper.GetParent(currentElement);
                    if (currentElement is not null
                        && dpd.DependencyProperty.OwnerType.IsInstanceOfType(currentElement))
                    {
                        return true;
                    }
                }
                while (attachedPropertyForChildren.IncludeDescendants && currentElement is not null);
            }

            // Check visual tree
            if (dependencyObject is Visual or Visual3D)
            {
                var currentElement = dependencyObject;
                do
                {
                    currentElement = VisualTreeHelper.GetParent(currentElement);
                    if (currentElement is not null
                        && dpd.DependencyProperty.OwnerType.IsInstanceOfType(currentElement))
                    {
                        return true;
                    }
                }
                while (attachedPropertyForChildren.IncludeDescendants && currentElement is not null);
            }

            return false;
        }

        var browsableForTypeAttributes = property.Attributes.OfType<AttachedPropertyBrowsableForTypeAttribute>();

        {
            var hadAttribute = false;
            foreach (var attachedPropertyForType in browsableForTypeAttributes)
            {
                hadAttribute = true;

                if (attachedPropertyForType.TargetType.IsInstanceOfType(target))
                {
                    return true;
                }
            }

            if (hadAttribute)
            {
                return false;
            }
        }

        var attachedPropertyForAttribute = (AttachedPropertyBrowsableWhenAttributePresentAttribute?)property.Attributes[typeof(AttachedPropertyBrowsableWhenAttributePresentAttribute)];

        if (attachedPropertyForAttribute is not null)
        {
            var dependentAttribute = TypeDescriptor.GetAttributes(target)[attachedPropertyForAttribute.AttributeType];
            if (dependentAttribute is not null)
            {
                return !dependentAttribute.IsDefaultAttribute();
            }

            return false;
        }

        return true;
    }
}